﻿using NetworkLib;
using PBO.Data;
using PBO.Game.BattleClass;
using PBO.Game.BattleLog;
using PBO.Game.Img;
using PBO.Util;
using PokemonBattle.BattleNetwork;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace PBO.Forms.NetworkForm.BattleForm
{
    public partial class BattleForm : Form
    {

        #region fields

        protected BattleLogger logger;
        private Battle _battle;

        protected TeamData _myTeamData;
        protected string _identity;
        protected byte _myPosition;
        protected BattleMode _battleMode;
        private BattleInfo _battleInfo;

        private object _locker = new object();
        protected ScreenUpPainter ScreenUp;
        protected ScreenDownPainter ScreenDown;

        #endregion

        public event VoidFunctionDelegate OnBattleStarted;

        public BattleForm()
        {
            InitializeComponent();
        }

        public BattleForm(string identity, byte indexValue, TeamData teamInfo, BattleMode mode)
        {
            InitializeComponent();

            // 在 InitializeComponent() 调用之后添加任何初始化。 
            this.Icon = Properties.Resources.PokemonBall;
            _myPosition = indexValue;
            _battleMode = mode;
#warning Validate?
            //teamInfo.Validate();
            _myTeamData = (TeamData)teamInfo.Clone();
            _identity = identity;

            logger = new BattleLogger();
            _battle = new Battle(logger, mode);
            SetPlayer(_myPosition, _identity);
            Initialize();
        }

        private void BindEvent()
        {
            this.ScreenDown.PlayerMoved += PlayerMoved;
            this.ScreenDown.Escape += ScreenDown_Escape;
            this.ScreenDown.Tie += ScreenDown_Tie;
            this.ScreenDown.StartShake += ScreenDown_StartShake;
            this.ScreenDown.StopShake += ScreenDown_StopShake;
            this.ScreenDown.ShowPokemonInfo += ScreenDown_ShowPokemonInfo;
            this.ScreenDown.HidePokemonInfo += ScreenDown_HidePokemonInfo;
        }

        private void Initialize()
        {
            if (!InvokeRequired)
            {
                int logLine = Convert.ToInt32(Properties.Settings.Default.LogLineCount);
                if (logLine > 6)
                {
                    rbLog.Size = new Size(256, 7 + logLine * 13);
                }
                if (Properties.Settings.Default.LogPosition == 0)
                {
                    if (logLine > 6)
                    {
                        this.Size = new Size(394, 439 + logLine * 13);
                    }
                }
                else
                {
                    this.Size = new Size(650, 432);
                    rbLog.Location = new Point(376, 45);
                }
                this.logger.LogAdded += this.AddMsg;
            }
            else
            {
                Invoke(new Action(Initialize));
            }
        }

        #region log msg

        private static void OutMsg(RichTextBox rtb, string msg, Color color)
        {
            if (rtb.IsDisposed) return;
            if (rtb.InvokeRequired)
            {
                rtb.Invoke(new Action(() => OutMsg(rtb, msg, color)));
            }
            else
            {
                rtb.SelectionStart = rtb.Text.Length;
                rtb.SelectionColor = color;
                rtb.AppendText(msg + "\r\n");
                rtb.ScrollToCaret();
            }
        }

        private void AddMsg(string msg, Color color)
        {
            OutMsg(this.rbLog, msg, color);
        }

        #endregion

        private void BattleForm_Load(object sender, EventArgs e)
        {

        }

        protected void SetCaption(string txt)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(delegate() { this.Text = txt; }));
            }
            else
            {
                this.Text = txt;
            }
        }

        protected void SetProgressText(string txt)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(delegate() { this.lblProgress.Text = txt; }));
            }
            else
            {
                this.lblProgress.Text = txt;
            }
        }

        protected void SetProgress(int value)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<int>(this.SetProgress), value);
            }
            else
            {
                this.pgbSendData.Value = value;
            }
        }

        protected void HideProgress()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(this.HideProgress));
            }
            else
            {
                lblProgress.Hide();
                pgbSendData.Hide();
            }
        }

        protected void PlayerMoved(PlayerBattleMove moveValue)
        {
            PlayerMove move = new PlayerMove();
            move.Move = moveValue.Move;
            move.MoveIndex = moveValue.MoveIndex;
            move.Pokemon = moveValue.PMIndex;
            move.Target = moveValue.TargetIndex;
            move.Player = _identity;
            //PlayerMoved(move);
#warning PlayerMoved
            ThreadPool.QueueUserWorkItem(RaiseMoved, move);
        }

        private void RaiseMoved(object obj)
        {
            PlayerMoved((PlayerMove)obj);
        }

        protected virtual void PlayerMoved(PlayerMove moveValue)
        {

        }

        public void SetMove(PlayerMove move)
        {
            lock (_locker)
            {
                _battle.SetMove(move);

                if ((_battle.MoveReady))
                {
                    TurnResult result = _battle.NextResult();
                    ScreenDown.SetTurnResult(result, _battle.GetPokemons(_myPosition).ToArray());
                    if (_battle.Ended)
                        OnBattleEnd();
                }
                if (ScreenDown.Moved == false)
                {
                    OnWaitMove();
                }
            }
        }

        protected virtual void OnWaitMove()
        {
        }

        public void SetRandomSeed(int seed)
        {
            _battle.RandomSeed = seed;
        }
        public void SetRules(List<BattleRule> rules)
        {
            _battle.Rules = rules;
        }
        public void SetPlayer(byte position, string identity)
        {
            _battle.SetPlayer(position, identity);
        }
        public bool PlayerReady
        {
            get { return _battle.PlayerReady; }
        }

        public void StartBattle(Dictionary<byte, TeamData> teamInfo)
        {
            _battle.SetTeams(teamInfo);
            _battle.InitializeBattle();
            if (OnBattleStarted != null)
            {
                OnBattleStarted();
            }

            foreach (byte key in teamInfo.Keys)
            {
                if (key != _myPosition)
                    PokemonCount(teamInfo[key]);
            }

            TurnResult result = _battle.StartBattle();

            ScreenUp = new ScreenUpPainter(picScreenUp, _battle.Ground.Terrain, logger, MyGroup, OpponentGroup, _battleMode);
            ScreenDown = new ScreenDownPainter(picScreenDown, _battle, _myPosition);
            BindEvent();
            SetCaption(_battle.GetCaption());
            ScreenUp.Paint();

            ScreenDown.SetTurnResult(result, _battle.GetPokemons(_myPosition).ToArray());
            OnWaitMove();
        }
        protected BattleSnapshot GetSnapshot(string text, Color color)
        {
            BattleSnapshot snapshot = new BattleSnapshot();
            snapshot.NewText = text;
            snapshot.TextColor = color.ToArgb();
            snapshot.Pokemons = new PokemonSnapshotSequence();
            snapshot.Pokemons.Elements.AddRange(_battle.SelectedPokemons.Select(p => GetPokemonSnap(p)));
            return snapshot;
        }
        private PokemonSnapshot GetPokemonSnap(Pokemon pm)
        {
            PokemonSnapshot pmSnap = new PokemonSnapshot();
            pmSnap.Identity = pm.BattleState.transfrom ? pm.BattleState.transTemp.Id : pm.Data.Id;
            pmSnap.Hp = Convert.ToInt16(pm.HealthPower);
            pmSnap.MaxHp = Convert.ToInt16(pm.MaxHp);
            pmSnap.Nickname = pm.NickName;
            pmSnap.State = Convert.ToByte(pm.State);
            pmSnap.Substituded = pm.BattleState.substituted;
            pmSnap.Hid = pm.BattleState.Hide;
            pmSnap.Lv = pm.LV;
            pmSnap.Gender = Convert.ToByte(pm.Gender);
            return pmSnap;
        }
        protected BattleInfo GetBattleInfo()
        {
            if (!_battle.BattleReady)
                return null;
            if (_battleInfo == null)
            {
                _battleInfo = new BattleInfo();
                _battleInfo.Mode = _battleMode;
                _battleInfo.Caption = this.Text;
                //_battleInfo.CustomDataHash = _myTeamData.CustomInfo.DataHash;
                _battleInfo.Terrain = _battle.Ground.Terrain;
            }
            return _battleInfo;
        }

        public BattleGroup MyGroup
        {
            get
            {
                if (_battle == null)
                    return null;
                switch (_myPosition)
                {
                    case 1:
                        return _battle.Group1;
                    case 2:
                        return _battleMode == BattleMode.Double_4P ? _battle.Group1 : _battle.Group2;
                    default:
                        return _battle.Group2;
                }
            }
        }

        public BattleGroup OpponentGroup
        {
            get
            {
                if (_battle == null)
                    return null;
                return MyGroup.Opponent;
            }
        }

        #region "ScreenDownEvent"

        private void ScreenDown_Escape(object sender, System.EventArgs e)
        {
            Close();
        }

        private void ScreenDown_Tie(object sender, System.EventArgs e)
        {
            SendTie();
        }

        private void ScreenDown_StartShake(object sender, System.EventArgs e)
        {
            ScreenUp.StartShake(ScreenDown.SelectedPokemon);
        }

        private void ScreenDown_StopShake(object sender, System.EventArgs e)
        {
            ScreenUp.StopShake();
        }

        private void ScreenDown_ShowPokemonInfo(Pokemon pokemon)
        {
            var text = new StringBuilder();
            text.AppendLine(pokemon.NickName);
            text.AppendLine(string.Format("LV : {0}", pokemon.LV));
            text.AppendLine(string.Format("HP : {0}/{1}", pokemon.HealthPower, pokemon.MaxHp));

            text.AppendLine("攻击 : " + pokemon.GetAttackValue());
            text.AppendLine("防御 : " + pokemon.GetDefenceValue());
            text.AppendLine("特攻 : " + pokemon.SpAttackValue);
            text.AppendLine("特防 : " + pokemon.SpDefenceValue);
            text.AppendLine("速度 : " + pokemon.SpeedValue);

            foreach (var move in pokemon.GetSelMoves())
            {
                text.AppendLine(" - " + move.Data.Name);
            }

            text.AppendLine("道具 : " + pokemon.GetItem().ToString());
            text.AppendLine("特性 : " + pokemon.GetSelTrait().ToString());
            PokemonLabel.Text = text.ToString();
            PokemonIcon.Image = pokemon.Icon;
        }

        private void ScreenDown_HidePokemonInfo(object sender, System.EventArgs e)
        {
            if (this.InvokeRequired)
            {
                Invoke(new Action<object, EventArgs>(ScreenDown_HidePokemonInfo), sender, e);
            }
            else
            {
                PokemonLabel.Text = "";
                PokemonLabel.Refresh();
                PokemonIcon.Image = null;
                PokemonIcon.Refresh();
            }
        }

        #endregion

        public void PlayerExit(string identity)
        {
            _battle.ExitGame(identity);
            BattleEnd();
            ScreenDown.Page = ScreenDownPainter.SelectedPage.Waiting;
        }
        private void SendTie()
        {
            DialogResult result = MessageBox.Show("即将想对手发送平手请求，是否确定？", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
            if (result == System.Windows.Forms.DialogResult.Yes)
            {
                ScreenDown.Moved = true;
                ScreenDown.Page = ScreenDownPainter.SelectedPage.Waiting;
                SendTieMessage(TieMessage.TieRequest);
            }
        }
        public void Tied()
        {
            _battle.Tie();
            BattleEnd();
        }
        public void GetTie(string player, TieMessage message)
        {
            if (message == TieMessage.TieRequest)
            {
                DialogResult result = ModShare.ShowInformation(this, player + "发出平手请求,是否同意", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    SendTieMessage(TieMessage.AgreeTie);
                }
                else if (result == System.Windows.Forms.DialogResult.No)
                {
                    SendTieMessage(TieMessage.RefuseTie);
                }
            }
            else if (message == TieMessage.RefuseTie)
            {
                ModShare.ShowInformation(this, "平手请求被" + player + "拒绝,对战继续", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                ScreenDown.Moved = false;
                ScreenDown.Page = ScreenDownPainter.SelectedPage.Index;
            }
            else if (message == TieMessage.AgreeTie)
            {
                Tied();
            }
            else if (message == TieMessage.Fail)
            {
                ModShare.ShowInformation(this, "当前无法提出平手请求", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                ScreenDown.Moved = false;
                ScreenDown.Page = ScreenDownPainter.SelectedPage.Index;
            }
        }

        protected virtual void SendTieMessage(TieMessage message)
        {
        }

        private void BattleEnd()
        {
            OnBattleEnd();
            ScreenDown.Moved = true;
        }
        protected virtual void OnBattleEnd()
        {
        }
        protected void OnError(string message)
        {
            ModShare.ShowInformation(this, message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            Invoke(new NetworkLib.VoidFunctionDelegate(Close));
        }

        private void BattleForm_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            OnEscape(e);
        }
        protected virtual void OnEscape(System.Windows.Forms.FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing && _battle != null)
            {
                DialogResult result = MessageBox.Show("是否退出对战?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
                if (result == System.Windows.Forms.DialogResult.Cancel)
                {
                    e.Cancel = true;
                    return;
                }
            }
            if (logger != null && logger.Any())
            {
                string path = FileHelper.GetLogSavePath(_battle._players);
                if (path.Length > 0)
                {
                    FileHelper.WriteToFile(path, logger);
                }
                if (_battle != null && _battle.Replay != null)
                    _battle.Replay.SaveReplay();
            }
            if (ScreenUp != null)
                ScreenUp.Dispose();
        }

        private static void PokemonCount(TeamData team)
        {
            foreach (PokemonCustomInfo pm in team.Pokemons)
            {
                GameService.PokemonCounter(pm.Identity);
            }
        }

        //重绘事件 采用F5
        private void BattleForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F5)
            {
                ScreenUp.Reset();
                ScreenDown.Reset();
            }
        }
    }
}
